package lion.blog.execution;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;

import lion.blog.model.BlogArticle;
import lion.blog.model.BlogCatelog;
import lion.blog.model.BlogComment;
import lion.blog.service.BlogService;
import lion.blog.util.BlogUtil;
import lion.dev.lang.MapJ;
import lion.dev.web.paging.PagedVo;
import lion.framework.core.bean.anno.Inject;
import lion.framework.core.db.SQLJoin;
import lion.framework.core.db.SessionFactory;
import lion.framework.core.db.paging.SQLPagingFactory;
import lion.framework.core.web.ApplicationContext;
import lion.framework.core.web.anno.MultiPath;
import lion.framework.core.web.anno.Namespace;
import lion.framework.core.web.anno.Path;
import lion.framework.core.web.anno.Result;
import lion.framework.core.web.anno.View;
import lion.framework.core.web.exception.WebException;
import lion.framework.core.web.path.PathVar;
import lion.framework.core.web.request.Request;
import lion.framework.core.web.views.ResultType;
import lion.web.platform.system.prop.PropService;
import lion.web.platform.system.prop.model.ModelProp;

/**
 * Blog前台显示
 * 
 * @author lion
 * @email hl_0074@sina.com
 * @date 2015年8月27日
 */
@Namespace(value = "/#{blog}", ref = "/#{blog}/index")
public class BlogExecution {

	@Inject("blog.blogService")
	private BlogService service;

	@Inject("platform.PropService")
	private PropService propService;

	/**
	 * 博客首页 有index.jsp的，和无index.jsp的,无index.jsp转向list页
	 */
	@Path("/index")
	@Result({ @View(name = "index", value = "/WEB-INF/blog/theme/{theme}/index.jsp"), @View(name = "list", value = "/#{blog}/p1", type = ResultType.FORWARD) })
	public String index(Request request) {

		request.addModel("theme", BlogUtil.getCurrentTheme());
		if (BlogUtil.hasFile("index.jsp")) { return "index"; }

		return "list";
	}

	/**
	 * 栏目首页或单独页
	 */
	@Path("/{catelog}")
	@Result({ @View(name = "list", value = "/WEB-INF/blog/theme/{theme}/list.jsp"), @View(name = "page", value = "/WEB-INF/blog/theme/{theme}/single/{page}.jsp") })
	public String pages(Request request, HttpServletRequest hsr) {

		String catelog = request.getString("catelog");
		if (StringUtils.isNotBlank(catelog)) {
			BlogCatelog blogCatelog = service.getBlogCatelog(catelog);
			if (blogCatelog != null) {
				this.list(request, hsr);
				return "list";
			}
		}

		if (!BlogUtil.hasFile("single/" + catelog + ".jsp")) {
			// page not found
			throw new WebException(404, "Page Not Found");
		}

		request.addModel("page", catelog);
		request.addModel("theme", BlogUtil.getCurrentTheme());
		return "page";
	}

	/**
	 * 文章列表页,栏目列表页
	 */
	@MultiPath({ @Path("/p{page:int}"), @Path("/{catelog}/{page:int}") })
	@Result(@View("/WEB-INF/blog/theme/{theme}/list.jsp"))
	public String list(Request request, HttpServletRequest hsr) {

		String catelog = request.getString("catelog");
		int page = request.getInt("page", 1);
		MapJ setting = (MapJ) ApplicationContext.get("blog");
		int size = setting.getInt("pageSize", 10);

		BlogCatelog blogCatelog = null;
		if (StringUtils.isNotBlank(catelog)) {
			blogCatelog = service.getBlogCatelog(catelog);
			if (blogCatelog == null) { throw new WebException(404, "Page Not Found"); }
		}

		MapJ param = new MapJ();

		SQLJoin sqlJoin = new SQLJoin();
		sqlJoin.add("draft=false");

		if (blogCatelog != null) {
			param.put("catelog", blogCatelog.getId());
			sqlJoin.add("catelog=:catelog");
		}
		PagedVo<BlogArticle> pagedVo = new PagedVo<>(BlogArticle.count("where " + sqlJoin.toString(), param));
		pagedVo.getPaging().setPageNumber(page);
		pagedVo.getPaging().setPageSize(size);

		sqlJoin.addSort("publishTime", "desc");

		pagedVo.setVos(
				BlogArticle.list(pagedVo.getPaging().getStartRowNumber(), pagedVo.getPaging().getPageSize(), "where " + sqlJoin.toString(), param, SessionFactory.getCurrentDB()));

		List<MapJ> articles = new ArrayList<>();
		for (BlogArticle article : pagedVo.getVos()) {
			articles.add(formatArticle(article, catelog));
		}
		request.addModel("articles", articles);
		request.addModel("paging", pagedVo.getPaging());
		request.addModel("catelog", blogCatelog);

		request.addModel("page", page);
		request.addModel("theme", BlogUtil.getCurrentTheme());

		// url pattern
		if (catelog == null) {
			request.addModel("pattern", hsr.getContextPath() + "/" + PathVar.getVar("blog") + "/p{page}");
		} else {
			request.addModel("pattern", hsr.getContextPath() + "/" + PathVar.getVar("blog") + "/" + catelog + "/p{page}");
		}

		return "success";
	}

	private MapJ formatArticle(BlogArticle article, String catelog) {

		// load Prop and other extern infos
		MapJ map = article.valueMap();
		map.put("url", BlogUtil.getBlogLink(map, catelog));
		map.put("catelog", service.getBlogCatelog(article.getCatelog()));
		for (ModelProp mp : propService.getModelProps("blog.article", article.getId())) {
			map.put(mp.getProp(), mp.getValue());
		}
		return map;
	}

	/**
	 * 
	 * 文章详细页
	 * 
	 * <pre>
	 *   /post/123
	 *   /post/hello-world
	 *   /post/catelog/id
	 *   /post/catelog/code
	 * </pre>
	 */
	@MultiPath({ @Path("/post/{id:int}"), @Path("/post/{alias}"), @Path("/post/{catelog}/{id:int}"), @Path("/post/{catelog}/{alias}") })
	@Result(@View("/WEB-INF/blog/theme/{theme}/{page}"))
	public String detail(Request request) {

		int id = request.getInt("id");
		String alias = request.getString("alias");
		String catelog = request.getString("catelog");

		BlogCatelog blogCatelog = null;
		if (StringUtils.isNotBlank(catelog)) {

			blogCatelog = service.getBlogCatelog(catelog);
			if (blogCatelog == null) { throw new WebException(" Catelog Not Found"); }
		}

		BlogArticle article = null;
		if (id > 0) {
			article = BlogArticle.load(id);
		} else if (StringUtils.isNotBlank(alias)) {
			article = service.getBlogArticle(alias);
		}
		if (article == null) { throw new WebException("Article Not Found"); }

		article.setReadCount(article.getReadCount() + 1);
		SessionFactory.getCurrentDB().update("update BlogArticle set readCount=? where id=?", article.getReadCount(), article.getId());

		// 按时间倒序
		request.addModel("pre", getOlderArticle(article, blogCatelog));// 早一篇文章
		request.addModel("next", getNewerArticle(article, blogCatelog));// 新一篇文章

		MapJ articleMap = formatArticle(article, catelog);
		request.addModel("article", articleMap);
		request.addModel("theme", BlogUtil.getCurrentTheme());
		String page = "detail.jsp";
		if (StringUtils.isNotBlank(article.getTemplate())) {
			page = article.getTemplate();
		}
		request.addModel("page", page);
		return "success";
	}

	/**
	 * 下一条文章
	 */
	private MapJ getNewerArticle(BlogArticle article, BlogCatelog catelog) {

		MapJ param = new MapJ();
		StringBuilder sql = new StringBuilder("where publishTime>:publishTime ");
		param.put("publishTime", article.getPublishTime());
		if (catelog != null) {
			sql.append(" and catelog=:catelog");
			param.put("catelog", catelog.getId());
		}
		sql.append(" order by publishTime desc");

		BlogArticle next = BlogArticle.load(SQLPagingFactory.paging(SessionFactory.getCurrentDB().getType(), sql.toString(), 0, 1), param, SessionFactory.getCurrentDB());

		if (next == null) { return null; }

		MapJ nextMap = next.valueMap();
		nextMap.put("url", BlogUtil.getBlogLink(nextMap, catelog == null ? "" : catelog.getCode()));

		return nextMap;
	}

	/**
	 * 上一条文章
	 */
	private MapJ getOlderArticle(BlogArticle article, BlogCatelog catelog) {

		MapJ param = new MapJ();
		StringBuilder sql = new StringBuilder("where publishTime<:publishTime ");
		param.put("publishTime", article.getPublishTime());
		if (catelog != null) {
			sql.append(" and catelog=:catelog");
			param.put("catelog", catelog.getId());
		}
		sql.append(" order by publishTime desc");

		BlogArticle pre = BlogArticle.load(SQLPagingFactory.paging(SessionFactory.getCurrentDB().getType(), sql.toString(), 0, 1), param, SessionFactory.getCurrentDB());

		if (pre == null) { return null; }

		MapJ preMap = pre.valueMap();
		preMap.put("url", BlogUtil.getBlogLink(preMap, catelog == null ? "" : catelog.getCode()));
		return preMap;
	}

	/**
	 * 标签页
	 */
	@MultiPath({ @Path("/tags"), @Path("/tags/{code}/"), @Path("/tags/{code}/p{page:int}") })
	@Result(@View("/WEB-INF/blog/theme/{theme}/list.jsp"))
	public String tag(Request request, HttpServletRequest hsr) {

		request.addModel("theme", BlogUtil.getCurrentTheme());

		String code = request.getString("code");
		if (StringUtils.isBlank(code)) { return "success"; }

		int page = request.getInt("page", 1);
		MapJ setting = (MapJ) ApplicationContext.get("blog");
		int size = setting.getInt("pageSize", 10);

		MapJ param = new MapJ();
		param.put("code", "%" + StringEscapeUtils.escapeSql(code) + "%");

		String where = "where tags like :code";
		PagedVo<BlogArticle> pagedVo = new PagedVo<>(BlogArticle.count(where, param));
		pagedVo.getPaging().setPageNumber(page);
		pagedVo.getPaging().setPageSize(size);

		List<BlogArticle> blogArticles = BlogArticle.list(pagedVo.getPaging().getStartRowNumber(), pagedVo.getPaging().getPageSize(), where, param, SessionFactory.getCurrentDB());

		pagedVo.setVos(blogArticles);

		List<MapJ> articles = new ArrayList<>();
		for (BlogArticle article : pagedVo.getVos()) {
			articles.add(formatArticle(article, null));
		}
		request.addModel("articles", articles);
		request.addModel("paging", pagedVo.getPaging());
		request.addModel("tag", code);

		request.addModel("page", page);
		request.addModel("theme", BlogUtil.getCurrentTheme());

		if (StringUtils.isNotBlank(code)) {
			code += "/";
		}

		// url pattern
		request.addModel("pattern", hsr.getContextPath() + "/" + PathVar.getVar("blog") + "/tags/" + code + "p{page}");

		request.addModel("theme", BlogUtil.getCurrentTheme());

		return "success";
	}

	/**
	 * 评论
	 */
	@Path("/comment/post")
	@Result({ @View(type = ResultType.JSON), @View(value = "/#{blog}/post/{article}?add=1", type = ResultType.REDIRECT) })
	public String saveComment(Request request) {

		BlogComment comment = BlogComment.create(request);

		BlogArticle blogArticle = service.getBlogArticle(comment.getArticle());
		if (blogArticle == null) { throw new WebException(404, "文章未找到"); }
		if (StringUtils.isBlank(comment.getName()) || StringUtils.isBlank(comment.getContent())) { throw new WebException(500, "评论信息不完整"); }

		comment.setCreateTime(new Date());
		comment.setIp(request.getRemoteAddr());
		comment.save();
		request.addModel("article", blogArticle.getId());

		return "success";
	}
}
